﻿using System;
using System.Web.Mvc;
using ValidationFramework.Reflection;
using ValidationFramework.Web.MVC.Configuration;

namespace ValidationFramework.Web.MVC
{
	/// <summary>
	/// Facade for ClientValidation script generation
	/// </summary>
	public static class ClientValidation
	{
		internal static bool IsInitialized { get; set; }
		internal static ClFunctionCallProviderDictionary scriptProviderDictionary;
		internal static IRuleConverter Converter { get; set; }

		public static void Initialize()
		{
			Initialize(null);
		}
		public static void Initialize(Action<IInitializationExpression> action)
		{
			lock (typeof(ClientValidation))
			{
				if (scriptProviderDictionary == null)
					scriptProviderDictionary = new ClFunctionCallProviderDictionary();

				var expression = new InitializationExpression();
				
				if (action != null)
					action(expression);

				InitializeScriptProviders(expression.GetProviderDictionary());

				Converter = new RuleConverter(scriptProviderDictionary);

				IsInitialized = true;
			}
		}

		private static void InitializeScriptProviders(ClFunctionCallProviderDictionary consumerScriptProviders)
		{

			// let the consumer override the default script providers
			foreach (var kvp in consumerScriptProviders)
			{
				if (scriptProviderDictionary.ContainsKey(kvp.Key))
					scriptProviderDictionary[kvp.Key] = kvp.Value;
				else
					scriptProviderDictionary.Add(kvp.Key, kvp.Value);
			}

		}

		public static string GenerateScripts(string htmlFormId, ViewContext viewContext)
		{
			return GenerateScripts(htmlFormId, viewContext, false);
		}
		public static string GenerateScripts(string htmlFormId, ViewContext viewContext, bool advancedMode)
		{
			var type = viewContext.ViewData.Model.GetType();
			return GenerateScriptsWithBlackList(htmlFormId, type, advancedMode, null);
		}

		public static string GenerateScripts(string htmlFormId, Type modelType)
		{
			return GenerateScripts(htmlFormId, modelType, false);
		}
		public static string GenerateScripts(string htmlFormId, Type modelType, bool advancedMode)
		{
			return GenerateScriptsWithBlackList(htmlFormId, modelType, advancedMode, null);
		}

		public static string GenerateScriptsForWhiteList(string htmlFormId, Type modelType, bool advancedMode, string whiteList)
		{
			if (!IsInitialized)
				Initialize();

			var typeKey = new TypeKey(modelType.TypeHandle);
			var strategy = new TypeExtractionStrategy(Validation.GetTypePolicy(typeKey));


			if (!string.IsNullOrEmpty(whiteList))
			{
				var propertyList = whiteList.Split(',');
				foreach (var item in propertyList)
				{
					strategy.AddToWhiteList(item);
				}
			}

			var engine = new ClientValidationEngine(new RuleExtractor(strategy), new JQueryGenerator(advancedMode), Converter);
			return engine.GenerateScript(htmlFormId);
		}

		public static string GenerateScriptsWithBlackList(string htmlFormId, Type modelType, bool advancedMode, string blackList)
		{
			if (!IsInitialized)
				Initialize();

			var typeKey = new TypeKey(modelType.TypeHandle);
			var strategy = new TypeExtractionStrategy(Validation.GetTypePolicy(typeKey));

			if (!string.IsNullOrEmpty(blackList))
			{
				var propertyList = blackList.Split(',');
				foreach (var item in propertyList)
				{
					strategy.AddToBlackList(item);
				}
			}

			var engine = new ClientValidationEngine(new RuleExtractor(strategy), new JQueryGenerator(advancedMode), Converter);
			return engine.GenerateScript(htmlFormId);
		}
	}
}
